package com.iplay.component.excel.core;

import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import com.iplay.component.excel.ExcelReader;
import com.iplay.component.excel.ExcelUtils;
import com.iplay.component.excel.annotation.Sheet;
import com.iplay.component.excel.exception.ExcelIOException;

@Component
public class DefaultExcelReader implements ExcelReader {

	private static final Logger LOGGER = LoggerFactory.getLogger(DefaultExcelReader.class);

	@Override
	public <T> List<T> loadAll(InputStream excel, Class<T> clazz) throws ExcelIOException {
		List<T> result = new LinkedList<>();
		String targetSheet = clazz.getSimpleName().toLowerCase();
		if (clazz.isAnnotationPresent(Sheet.class)) {
			targetSheet = clazz.getAnnotation(Sheet.class).value();
		}
		List<String[]> data = ExcelUtils.readExcel(excel, targetSheet);
		if (!(data.size() > 0 && data.get(0).length > 0))
			return result;
		String[] header = data.get(0);
		Map<String, Integer> columnIndexMap = new HashMap<>();
		for (int i = 0; i < header.length; i++) {
			columnIndexMap.put(header[i], i);
		}
		List<ColumnMetaData> columnMetaDatas = new LinkedList<>();
		ReflectionUtils.doWithFields(clazz, field -> {
			ColumnMetaData columnMetaData = new ColumnMetaData(field);
			String columnName = columnMetaData.getColumnName();
			if (columnIndexMap.containsKey(columnName)) {
				columnMetaData.setColumnIndex(columnIndexMap.get(columnName));
				columnMetaDatas.add(columnMetaData);
			}
		});
		try {
			for (int i = 1; i < data.size(); i++) {
				T newInstance = clazz.newInstance();
				String[] row = data.get(i);
				for (ColumnMetaData meta : columnMetaDatas) {
					Object value = row[meta.getColumnIndex()];
					@SuppressWarnings("unchecked")
					Converter<Object, Object> converter = meta.getConverter();
					if (converter != null)
						value = converter.convert(value);
					meta.getField().setAccessible(true);
					meta.getField().set(newInstance, value);
				}
				result.add(newInstance);
			}

		} catch (InstantiationException | IllegalAccessException e) {
			LOGGER.error(e.getMessage(), e);
			throw new ExcelIOException(e.getMessage(), e);
		}
		return result;
	}

	@Override
	public <T> List<T> filter(InputStream excel, Class<T> holderClass, Predicate<T> predicate) throws ExcelIOException {
		return null;
	}

}
